//
// Created by hugan on 2021/9/12.
//
#include <iostream>
#include <windows.h>
#include "sphelper.h"

using namespace std;

void printErrCode() {
    //服务未注册:未安装
    cout << "REGDB_E_CLASSNOTREG" << REGDB_E_CLASSNOTREG << endl;
    //SetVoice
    cout << "E_INVALIDARG" << E_INVALIDARG << endl;
    //ISpVoice.Speak
    //未SetVoice时调用speak=-2147024891,不在官网的错误码中,或h中找不到此值
    cout << "E_INVALIDARG" << E_INVALIDARG << endl;
    cout << "E_POINTER" << E_POINTER << endl;
    cout << "E_OUTOFMEMORY" << E_OUTOFMEMORY << endl;
}

void doTest() {
    /*
     * 获取ISpVoice
     * https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms719576(v=vs.85)
     */
    ISpVoice *pVoice = nullptr;
    HRESULT hr = CoCreateInstance(CLSID_SpVoice, nullptr, CLSCTX_ALL, IID_ISpVoice, (void **) &pVoice);
    if (FAILED(hr)) {
        cout << "initErr=" << hr << endl;
        return;
    }

    //获取IEnumSpObjectTokens
    IEnumSpObjectTokens *pSpEnumTokens = nullptr;
    if (FAILED(hr = SpEnumTokens(SPCAT_VOICES, nullptr, nullptr, &pSpEnumTokens))) {
        cout << "pSpEnumTokens.err=" << hr << endl;
        return;
    }

    //语音引擎数量
    ULONG ulTokensNumber = 0;
    pSpEnumTokens->GetCount(&ulTokensNumber);
    cout << "voiceNum=" << ulTokensNumber << endl;

    //遍历语音引擎,并朗读文本
    ISpObjectToken *pSpToken = nullptr;
    while (SUCCEEDED(pSpEnumTokens->Next(1, &pSpToken, nullptr)) && pSpToken != nullptr) {
        //id和desc是一样的
        wchar_t *id = nullptr;
        pSpToken->GetId(&id);
        wcout << "id=" << id << endl;
        wstring name = wstring(id);
        wcout << "name=" << name.substr(name.find_last_of('\\') + 1) << endl;

        //设置语音引擎,网上很多资料少了这句导致没播放成功
        pVoice->SetVoice(pSpToken);
        pVoice->SetVolume(100);
        pVoice->SetRate(2);
        hr = pVoice->Speak(L"hello,今天的天气真好啊", SPF_DEFAULT, nullptr);     // 朗读中文和英文的混合字符串
        cout << "Speak.res=" << hr << endl;
        pSpToken->Release();
    }
    pSpEnumTokens->Release();
}

int main() {
    cout << "1" << endl;

    printErrCode();

    //COM初始化：
    if (SUCCEEDED(::CoInitialize(nullptr))) {
        doTest();
        ::CoUninitialize();
    }
//    Sleep(13000);
    cout << "ed" << endl;
    return 0;
}